﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2013 Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#include "GLESObjectManager.h"
#include "GLESStateManager.h"

namespace UX_STL
{
namespace GLESshell
{

/*
=================================================
	конструктор
=================================================
*/
	GLESObjectManager::GLESObjectManager()
	{
	}
	
/*
=================================================
	деструктор
=================================================
*/
	GLESObjectManager::~GLESObjectManager()
	{
	}
	
/*
=================================================
	получить индексы свободных VAO
=================================================
*/
	bool GLESObjectManager::GenVertexArrays(const GLsizei n, GLuint * arrays)
	{
		GL_CALL_R( OES_vertex_array_object::glGenVertexArrays( n, arrays ) );
		return true;
	}

/*
=================================================
	освободить индексы VAO
=================================================
*/
	bool GLESObjectManager::DeleteVertexArrays(const GLsizei n, const GLuint * arrays)
	{
		GL_CALL_R( OES_vertex_array_object::glDeleteVertexArrays( n, arrays ) );
		return true;
	}
	
/*
=================================================
	устанавливает атрибуты для VAO в текущем контексте
=================================================
*/
	bool GLESObjectManager::s_SetAttribs(GLuint uVAO, const uni_array<const GLESVertexAttribExt> &aAttribs)
	{
		bool	b_res = true;

		// dsable all attribs
		for (int i = 0; i < C_GL_MAX_VERTEX_ATTRIBS; ++i) {
			GL_CALL( glDisableVertexAttribArray( i ) );
		}

		FOR( i, aAttribs )
		{
			GLESVertexAttribExt const &	attrib = aAttribs[i];
			
			
			if ( attrib.uLocation == MaxValue(attrib.uLocation) )
				continue;

			ASSERT( attrib.uLocation < C_GL_MAX_VERTEX_ATTRIBS );

			SMAN()->BindVertexArray( uVAO );
			
			GL_CALL_BA( glEnableVertexAttribArray( attrib.uLocation ), b_res );

			GL_CALL_BA( glVertexAttribPointer(	attrib.uLocation,
												attrib.uCount,
												attrib.eType,
												attrib.bNormalize,
												attrib.uStride,
												(const void *)attrib.uOffset ), b_res );
		}

		return b_res;
	}
	
/*
=================================================
	возвращает атрибуты VAO в текущем контексте
=================================================
*/
	bool GLESObjectManager::s_GetAttribs(GLuint uVAO, GLESVerticesAttribsExt_t &aAttribs)
	{
		SMAN()->PushVertexArray();
		SMAN()->BindVertexArray( uVAO );

		for (int i = 0; i < C_GL_MAX_VERTEX_ATTRIBS; ++i)
		{
			bool	b_ret	= true;
			GLint	i_temp	= 0;

			GL_CALL_BA( glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &i_temp ), b_ret );

			if ( i_temp != GL_TRUE )
				continue;

			GLESVertexAttribExt	s_attrib;
			void		*		ptr;
			
			s_attrib.uLocation	= i;

			GL_CALL_BA( glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &i_temp ), b_ret );
			s_attrib.uBuffer	= (uint)i_temp;

			GL_CALL_BA( glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &i_temp ), b_ret );
			s_attrib.uStride	= (uint)i_temp;
			
			GL_CALL_BA( glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &i_temp ), b_ret );
			s_attrib.uCount		= (uint)i_temp;
			
			GL_CALL_BA( glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &i_temp ), b_ret );
			s_attrib.eType		= (gl_vertex::type)i_temp;

			GL_CALL_BA( glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &i_temp ), b_ret );
			s_attrib.bNormalize	= !!i_temp;
			
			GL_CALL_BA( glGetVertexAttribPointerv( i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr ), b_ret );
			s_attrib.uOffset	= (uint)ptr;

			if ( !b_ret ) {
				LOG_WARNING( "GL errors while get attrib params, location: " << i, e_log_msg::ERROR_4 );
				b_ret = true;
			}

			aAttribs.PushBack( s_attrib );
		}

		SMAN()->PopVertexArray();
		return true;
	}

/*
=================================================
	проверяет остались ли не удаленные объекты
=================================================
*/
	void GLESObjectManager::CheckNotReleasedObjects()
	{
#	define CHECK_GL_OBJ( _val, _name )		if ( _val > 0 ) { b_leak = true;  s_info << _name << ": " << _val << "\n"; }

		string			s_info( "Check memory leaks:\n" );
		bool			b_leak = false;
		GLESStatistic *	p_stat = SMAN()->GetStatistic();

		CHECK_GL_OBJ( p_stat->uBuffers,				"buffers" );
		CHECK_GL_OBJ( p_stat->uFrameBuffers,		"framebuffers" );
		CHECK_GL_OBJ( p_stat->uProgramPipelines,	"program pipelines" );
		CHECK_GL_OBJ( p_stat->uPrograms,			"programs" );
		CHECK_GL_OBJ( p_stat->uQueries,				"queries" );
		CHECK_GL_OBJ( p_stat->uRenderBuffers,		"renderbuffers" );
		CHECK_GL_OBJ( p_stat->uShaders,				"shaders" );
		CHECK_GL_OBJ( p_stat->uTextures,			"textures" );
		CHECK_GL_OBJ( p_stat->uVAOs,				"vertex arrays" );

		if ( b_leak )
			LOG( s_info.cstr(), e_log_msg::WARNING_NL_0 );

#	undef CHECK_GL_OBJ
	}

/*
=================================================
	обертки на GL-функциями
=================================================
*/
	bool GLESObjectManager::GenBuffers(GLsizei n, GLuint * buffers) const
	{
		GL_CALL_R( glGenBuffers( n, buffers ) );
		SMAN()->GetStatistic()->uBuffers += n;
		return true;
	}


	bool GLESObjectManager::GenFramebuffers(GLsizei n, GLuint * ids) const
	{
		GL_CALL_R( glGenFramebuffers( n, ids ) );
		SMAN()->GetStatistic()->uFrameBuffers += n;
		return true;
	}


	bool GLESObjectManager::GenProgramPipelines(GLsizei n, GLuint * pipelines) const
	{
		GL_CALL_R( EXT_separate_shader_objects::glGenProgramPipelines( n, pipelines ) );
		SMAN()->GetStatistic()->uProgramPipelines += n;
		return true;
	}


	bool GLESObjectManager::GenQueries(GLsizei n, GLuint * ids) const
	{
		GL_CALL_R( EXT_occlusion_query_boolean::glGenQueries( n, ids ) );
		SMAN()->GetStatistic()->uQueries += n;
		return true;
	}


	bool GLESObjectManager::GenRenderbuffers(GLsizei n, GLuint * renderbuffers) const
	{
		GL_CALL_R( glGenRenderbuffers( n, renderbuffers ) );
		SMAN()->GetStatistic()->uRenderBuffers += n;
		return true;
	}


	bool GLESObjectManager::GenTextures(GLsizei n, GLuint * textures) const
	{
		GL_CALL_R( glGenTextures( n, textures ) );
		SMAN()->GetStatistic()->uTextures += n;
		return true;
	}

	bool GLESObjectManager::CreateShader(GLenum shaderType, GLuint &shader) const
	{
		GL_CALL_R( shader = glCreateShader( shaderType ) );
		SMAN()->GetStatistic()->uShaders++;
		return true;
	}


	bool GLESObjectManager::CreateProgram(GLuint &program) const
	{
		GL_CALL_R( program = glCreateProgram() );
		SMAN()->GetStatistic()->uPrograms++;
		return true;
	}



	bool GLESObjectManager::DeleteBuffers(GLsizei n, const GLuint * buffers) const
	{
		GL_CALL_R( glDeleteBuffers( n, buffers ) );
		SMAN()->GetStatistic()->uBuffers -= n;
		return true;
	}


	bool GLESObjectManager::DeleteFramebuffers(GLsizei n, const GLuint * ids) const
	{
		GL_CALL_R( glDeleteFramebuffers( n, ids ) );
		SMAN()->GetStatistic()->uFrameBuffers -= n;
		return true;
	}


	bool GLESObjectManager::DeleteProgramPipelines(GLsizei n, const GLuint * pipelines) const
	{
		GL_CALL_R( EXT_separate_shader_objects::glDeleteProgramPipelines( n, pipelines ) );
		SMAN()->GetStatistic()->uProgramPipelines -= n;
		return true;
	}


	bool GLESObjectManager::DeleteQueries(GLsizei n, const GLuint * ids) const
	{
		GL_CALL_R( EXT_occlusion_query_boolean::glDeleteQueries( n, ids ) );
		SMAN()->GetStatistic()->uQueries -= n;
		return true;
	}


	bool GLESObjectManager::DeleteRenderbuffers(GLsizei n, const GLuint * renderbuffers) const
	{
		GL_CALL_R( glDeleteRenderbuffers( n, renderbuffers ) );
		SMAN()->GetStatistic()->uRenderBuffers -= n;
		return true;
	}


	bool GLESObjectManager::DeleteTextures(GLsizei n, const GLuint * textures) const
	{
		GL_CALL_R( glDeleteTextures( n, textures ) );
		SMAN()->GetStatistic()->uTextures -= n;
		return true;
	}


	bool GLESObjectManager::DeleteShader(GLuint shader) const
	{
		GL_CALL_R( glDeleteShader( shader ) );
		SMAN()->GetStatistic()->uShaders--;
		return true;
	}


	bool GLESObjectManager::DeleteProgram(GLuint program) const
	{
		GL_CALL_R( glDeleteProgram( program ) );
		SMAN()->GetStatistic()->uPrograms--;
		return true;
	}
	
//-------------------------------------------------------------------
	
}	// GLShell
}	// UX_STL